#include "hlw8012.h"
#include <stdbool.h>
#include "tim.h"

// 定时器相关变量
static TIM_HandleTypeDef *hlw_tim;

// 捕获相关变量
volatile uint32_t last_captured_cf = 0, last_captured_cf1 = 0;
volatile uint32_t period_cf = 0, period_cf1 = 0;
volatile uint32_t overflow_count_cf = 0, overflow_count_cf1 = 0;
static bool first_capture_cf = true, first_capture_cf1 = true;

//功率超时
volatile uint32_t last_cf_capture_time = 0;  // 记录最后一次CF捕获的时间戳（毫秒）
static const uint32_t CF_PULSE_TIMEOUT = 1000; 

//卡尔曼滤波
static KalmanFilter voltage_filter = {0};
static KalmanFilter power_filter = {0};

/*
Typical values are:  典型值为：

A 1Hz pulse on CF pin means around 12W RMS
CF 引脚上的 1Hz 脉冲表示大约 12W RMS
A 1Hz pulse on CF1 pin means 15mA or 0.5V RMS depending on the value in SEL pin
CF1 引脚上的 1Hz 脉冲表示 15mA 或 0.5V RMS，具体取决于 SEL 引脚中的值
*/

// 校准系数
// 实际值    周期
// 232.5     1640
// 30w       311584  //功率越大周期越小   
static const float VOLTAGE_RATIO = 0.37246f;    // 电压校准系数
static const float CURRENT_RATIO = 1000.0f;   // 电流校准系数
static const float POWER_RATIO = 6.378f;        // 功率校准系数


// 电能累计
static float accumulated_energy = 0.0f;
static uint32_t last_energy_update = 0;

/* 新增卡尔曼滤波更新函数 */
static float Kalman_Update(KalmanFilter *kf, float measurement)
{
    /* 预测步骤 */
    kf->P += kf->Q;
    
    /* 更新步骤 */
    float K = kf->P / (kf->P + kf->R); // 卡尔曼增益
    kf->x += K * (measurement - kf->x);
    kf->P *= (1 - K);
    
    return kf->x;
}

/**​
  * @brief  HLW8012初始化
  * @param  htim 定时器句柄
  * @retval None
  */
void HLW8012_Init(TIM_HandleTypeDef *htim)
{
  hlw_tim = htim;

  // 启动定时器和输入捕获通道
  HAL_TIM_Base_Start(htim);
  HAL_TIM_IC_Start_IT(htim, TIM_CHANNEL_3); // CF1 电压
  HAL_TIM_IC_Start_IT(htim, TIM_CHANNEL_4); // CF  功率

  // 使能更新中断(用于溢出计数)
  __HAL_TIM_ENABLE_IT(htim, TIM_IT_UPDATE);
  
  //卡尔曼滤波
  // 初始化卡尔曼滤波器参数
    voltage_filter = (KalmanFilter){
        .Q = 0.0001f,   // 过程噪声方差（根据实际情况调整）
        .R = 10.0f,    // 测量噪声方差（根据实际情况调整）
        .x = 220.0f,  // 初始电压估计值
        .P = 1.0f
    };
    
    power_filter = (KalmanFilter){
        .Q = 0.3f,  //增大 跟手
        .R = 10.0f,  //增大 更稳定
        .x = 0.0f,    // 初始功率估计值
        .P = 1.0f
    };
}

/**​
  * @brief  输入捕获回调函数（精简版）
  */
void HLW8012_CaptureCallback(TIM_HandleTypeDef *htim)
{
  // 通道3（CF1）捕获 - 电压
  if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_3) {
    uint32_t capture = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_3);

    if (!first_capture_cf1) {
      period_cf1 = (capture >= last_captured_cf1) ?
                   (capture - last_captured_cf1 + overflow_count_cf1 * htim->Instance->ARR) :
                   (htim->Instance->ARR - last_captured_cf1 + capture + overflow_count_cf1 * htim->Instance->ARR);
    }
    last_captured_cf1 = capture;
    overflow_count_cf1 = 0;
    first_capture_cf1 = false;
  }

  // 通道4（CF）捕获 - 电流/功率
  else if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_4) {
    uint32_t capture = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_4);

    if (!first_capture_cf) {
      period_cf = (capture >= last_captured_cf) ?
                  (capture - last_captured_cf + overflow_count_cf * htim->Instance->ARR) :
                  (htim->Instance->ARR - last_captured_cf + capture + overflow_count_cf * htim->Instance->ARR);
    }
    last_captured_cf = capture;
    overflow_count_cf = 0;
    first_capture_cf = false;
    last_cf_capture_time = HAL_GetTick(); // 更新最后一次捕获时间
  }
}

/**​
  * @brief  定时器溢出回调（单独处理溢出）
  */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  if (htim == hlw_tim) {
    overflow_count_cf++;
    overflow_count_cf1++;
  }
}
/**
  * @brief  获取电压值(V)
  * @note   1Hz CF1 脉冲 ≈ 0.5V RMS（当 SEL 为高电平时）
  * @retval 电压值
  */
float HLW8012_GetVoltage(void)
{
    if (period_cf1 <= 0) return 0.0f;
    float raw = VOLTAGE_RATIO / period_cf1 * 1000000;
    return Kalman_Update(&voltage_filter, raw);
}

/**
  * @brief  获取电流值(A)
  * @note   1Hz CF1 脉冲 ≈ 15mA（当 SEL 为低电平时）
  * @retval 电流值
  */
float HLW8012_GetCurrent(void)
{
    float voltage = HLW8012_GetVoltage();
    if (voltage < 1.0f) return 0.0f;  // 防止除以极小值
    
    float raw = HLW8012_GetPower() / voltage;
    return raw;
}

/**
  * @brief  获取功率值(W)
  * @note   1Hz CF 脉冲 ≈ 12W RMS
  * @retval 功率值
  */
float HLW8012_GetPower(void)
{
    if (last_cf_capture_time == 0 || 
        (HAL_GetTick() - last_cf_capture_time) >= CF_PULSE_TIMEOUT) {
        return Kalman_Update(&power_filter, 0.0f);
    }
    if (period_cf <= 0) return 0.0f;
    float raw = POWER_RATIO / period_cf * 1000000;
    return Kalman_Update(&power_filter, raw);
}


/**​
  * @brief  获取累计电能(kWh)
  * @retval 累计电能
  */
float HLW8012_GetEnergy(void)
{
  uint32_t now = HAL_GetTick();
  float time_elapsed = (float)(now - last_energy_update) / 3600000.0f; // 毫秒转小时

  // 累计电能 = 功率(W) * 时间(h) / 1000 → 转换为kWh
  accumulated_energy += HLW8012_GetPower() * time_elapsed / 1000.0f;
  last_energy_update = now;

  return accumulated_energy;
}

/**​
  * @brief  重置累计电能
  * @retval None
  */
void HLW8012_ResetEnergy(void)
{
  accumulated_energy = 0.0f;
  last_energy_update = HAL_GetTick();
}

/**​
  * @brief  进行一次电能检测
  * @retval None
  */
HLW8012_Data get_hlw_data(void)
{
  HLW8012_Data data = {0};

  // 停止定时器和捕获通道，确保处于初始状态
  HAL_TIM_IC_Stop_IT(hlw_tim, TIM_CHANNEL_3);
  HAL_TIM_IC_Stop_IT(hlw_tim, TIM_CHANNEL_4);
  HAL_TIM_Base_Stop(hlw_tim);

  // 重置捕获相关变量，开始新的测量周期
  first_capture_cf = true;
  first_capture_cf1 = true;
  period_cf = 0;
  period_cf1 = 0;
  last_captured_cf = 0;
  last_captured_cf1 = 0;
  overflow_count_cf = 0;
  overflow_count_cf1 = 0;

  // 启动定时器和输入捕获
  HAL_TIM_Base_Start(hlw_tim);
  HAL_TIM_IC_Start_IT(hlw_tim, TIM_CHANNEL_3); // CF1 电压
  HAL_TIM_IC_Start_IT(hlw_tim, TIM_CHANNEL_4); // CF  功率

  // 等待数据稳定，最多等待200ms
  uint32_t start_tick = HAL_GetTick();
  while ((period_cf == 0 || period_cf1 == 0) && (HAL_GetTick() - start_tick < 1000)) {
    // 空循环，等待捕获完成或超时
  }

  // 读取稳定后的数据
  data.voltage = HLW8012_GetVoltage();
  data.current = HLW8012_GetCurrent();
  data.power = HLW8012_GetPower();
  data.energy = HLW8012_GetEnergy();


  // 停止定时器以节省资源
  HAL_TIM_IC_Stop_IT(hlw_tim, TIM_CHANNEL_3);
  HAL_TIM_IC_Stop_IT(hlw_tim, TIM_CHANNEL_4);
  HAL_TIM_Base_Stop(hlw_tim);

  return data;
}

// 定时器输入捕获回调函数
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
  if (htim == hlw_tim) {
    HLW8012_CaptureCallback(htim);
  }
}

